# -*- coding: utf-8 -*-
#pylint: disable-msg=W0212
'''
Created on 09/ott/2009

@author: sax
'''

from django.conf import settings
from django.contrib import admin
from django.contrib.admin import site
from django.core.urlresolvers import reverse, NoReverseMatch
from django.test import TestCase
from testapp.models import *

class ViewTestCase( TestCase ):
    def __init__(self, methodName='runTest'):
        assert 'testapp' in settings.INSTALLED_APPS
        assert 'xadmin' in settings.INSTALLED_APPS
        assert hasattr(settings, 'DEBUG_USER')
        assert hasattr(settings, 'DEBUG_PASSWORD')
                      
        super(ViewTestCase,self).__init__(methodName)

    def login(self, username=settings.DEBUG_USER, password=settings.DEBUG_PASSWORD):
        self.client.login(username=username, password=password)
        self.failUnless("sessionid" in self.client.cookies, "Unable to login %s:%s" % (username, password) )
        
    def logout(self):
        #try:
        self.client.logout()
            #del self.client.cookies["sessionid"]
        self.failIf("sessionid" in self.client.cookies, "Unable to logout" )
        #except KeyError:
        #    pass
    
    def get_secured(self, path, data={}, follow=False, **extra):
        self.login()
        return self.client.get(path, data, follow, **extra)
    
    def is_login_page(self, response):
        return ("username" in response.content) and \
                ("password" in response.content) and \
                ("login" in response.content) and \
                response.status_code == 200
                
    def check_secured(self, url, check=lambda r: r.status_code == 200, username=settings.DEBUG_USER, password=settings.DEBUG_PASSWORD, message=""):
        """ test a login request for url 
            check is a tuple of:
            [0] string to search into response 
            [1] number of occurence of string            
        """
        self.logout()            
        response = self.client.get(url)
        assert self.is_login_page(response), "Unable to logout" 
        self.login(username=username, password=password)            
        response = self.client.get(url)
        assert check(response), message
        
        return response

#    def assert_tag_contains(self, response, tag, value, count=None, status_code=200):
#        self.assertEqual(response.status_code, status_code,
#            "Couldn't retrieve page: Response code was %d (expected %d)'" %
#                (response.status_code, status_code))   
#
#        v = smart_str(value, response._charset)
#        target = "<%s>.*%s.*</%s>" % (tag, value, tag)
#        t = value
#        
#        m = re.findall(target, response.content)                
#        self.failUnless(m, "Couldn't find %s in response" % t )
#
#        real_count = len(m)
#        if count is not None:
#            self.assertEqual(real_count, count,
#                "Found %d instances of [%s] in response (expected %d)" %
#                    (real_count, t, count))
#        else:
#            self.failUnless(real_count != 0,  "Couldn't find %s in response" % t)
        
             
#    def assert_contains_input(self, response, name, value=None, count=None, status_code=200):
#        self.assertEqual(response.status_code, status_code,
#            "Couldn't retrieve page: Response code was %d (expected %d)'" %
#                (response.status_code, status_code))   
#             
#        
#        n = smart_str(name, response._charset)
#        v = smart_str(value, response._charset)
#        if value:
#            target = "<input.*?name=['\"]%s['\"].*?value=[\"']%s[\"'].*?>" % (n,v)
#            t = "input with name='%s' and value='%s'"  % (n,v)
#        else:
#            target = "<input.*?name=['\"]%s['\"].*?>" % n
#            t = "input with name='%s'"  % n
#        
#        
#        m = re.findall(target, response.content)                
#        self.failUnless(m, "Couldn't find %s in response" % t )
#        
#        #m2 = re.findall("<input.*?value=[\"']%s[\"'].*?>" % text, response.content)
#        
#        real_count = len(m)
#        if count is not None:
#            self.assertEqual(real_count, count,
#                "Found %d instances of [%s] in response (expected %d)" %
#                    (real_count, t, count))
#        else:
#            self.failUnless(real_count != 0,  "Couldn't find %s in response" % t)


                    
class AdminTestCase( ViewTestCase ): 
    model = None
    fixtures = ['initial_data']
    
    
    def __init__(self, methodName='runTest'):
        if self.model is None:
            raise Exception("Please set [model] attribute to %s" % self.__class__.__name__)        
        self.admin_site = admin.site
        super(AdminTestCase, self).__init__(methodName)

    def _get_admin_model(self):
        return site._registry.get(self.model)
    
    admin_model = property(_get_admin_model)
    
    def _get_view_name(self, action):
        return  '%s_%s_%s' % (self.model._meta.app_label, 
                            self.model._meta.module_name,
                            action)        
    
    def _reverse(self, viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
        try:
            return reverse( "%s:%s" % (self.admin_site.name, viewname),
                        urlconf, args, kwargs, prefix, current_app)
            
        except NoReverseMatch, e:
            #self.failureException = e
            self.fail( "Error reversing %s" % "%s:%s" % (self.admin_site.name, viewname))
                
    def _test_list(self, extraargs= ""):
        import django.contrib.admin.views.main
        view_name = self._get_view_name("changelist")
        url = self._reverse( view_name )                
        ret = self.get_secured( url +  extraargs )
        self.assertTrue( isinstance(ret.context['cl'], django.contrib.admin.views.main.ChangeList)) 
        return ret
    
    def _get_values_from_form(self, response):
        from BeautifulSoup import BeautifulSoup
        soup = BeautifulSoup( str(response.content) )
        values = None
        if soup.form:
            inputs = soup.form.findAll(name='input')
            values = {}
            for i in inputs:          
                if i.get('name')[0] != "_":
                    values[ i['name'] ] = i.get('value',"")
        return values
            
    def _test_edit_post(self, pk, values={}):
        # test an edit and post with the rendered data
        # we need to test that widgets render all data
        # aka: hidden readonly/modellink 
        try:
            view_name = self._get_view_name("change")            
            url = self._reverse( view_name, args=[pk] )
            
            view_list = self._get_view_name("changelist")
            view_url = self._reverse( view_list )    
            
            target = self.model.objects.get(pk=pk)     
                             
            ret = self.get_secured( url )
            
            v = self._get_values_from_form ( ret )
            v.update(values)
            ret = self.client.post( url, v )
            try:
                self.assertRedirects(ret, view_url)
            except AssertionError, e:
                errs =  repr(ret.context['adminform'].form.errors)
                raise Exception("Cannot save record (%s)." % errs, e)
        
        except ImportError:
            pass
        
    def _test_edit(self, pk, name=None, value=None,*assertArgs, **assertKwArgs):
        view_name = self._get_view_name("change")
        url = self._reverse( view_name, args=[pk] )
        target = self.model.objects.get(pk=pk)                      
        ret = self.get_secured( url )
        self.assertEqual( ret.context['original'], target)
        return ret

    def _test_delete(self, pk, *assertArgs, **assertKwArgs):
        view_name = self._get_view_name("delete")
        url = self._reverse( view_name, args=[pk] )                
        target = self.model.objects.get(pk=pk)
        ret = self.get_secured( url )
        self.assertEqual( ret.context['object'], target)
        return ret

    def _test_history(self, pk, *assertArgs, **assertKwArgs):
        view_name = self._get_view_name("history")
        url = self._reverse( view_name, args=[pk] )                
        target = self.model.objects.get(pk=pk)
        ret = self.get_secured( url )
        self.assertEqual( ret.context['object'], target)
        self.assertEqual( ret.context['title'], u'Change history: %s' % str(target))
        return ret

    def _test_add(self, input_name="", form_name="", *assertArgs, **assertKwArgs):
        view_name = self._get_view_name("add")
        url = self._reverse( view_name )                
        ret = self.get_secured( url )        
        self.assertFalse( ret.context['show_delete'] )
        self.assertFalse( ret.context['change'] )
        self.assertTrue( ret.context['add'] )
        return ret
